#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <string>
#include <cstring>
#include <iostream>
#include <unistd.h>
#include <pthread.h>
#include "Log.hpp"
#include"ThreadPool.hpp"


Log lg;

using namespace std;

#define defaultPort 8888
#define defaultIp "0.0.0.0"

enum
{
    USAGEERR = 1,
    SOCKETERR,
    BINDERR,
    LISTENERR
};

class ThreadData{
public:
    ThreadData(int sockfd)
    :sockfd_(sockfd)
    {}

public:
    int sockfd_;
};

class TcpServer
{
public:
    TcpServer(string ip = defaultIp, uint16_t port = defaultPort)
        : port_(port), ip_(ip)
    {
        t.start();
    }

    void Init()
    {
        listenfd_ = socket(AF_INET, SOCK_STREAM, 0);
        if (listenfd_ < 0)
        {
            lg(Fatal, "socket Fail,sockfd:%d,code:%d,strerror:%s", listenfd_, errno, strerror(errno));
            exit(SOCKETERR);
        }
        lg(Info, "socket Success,listenkfd:%d,code:%d,str:%s", listenfd_, errno, strerror(errno));

        struct sockaddr_in lock;
        socklen_t len = sizeof(lock);
        memset(&lock, 0, len);
        lock.sin_family = AF_INET;
        lock.sin_port = htons(port_);
        // inet_pton(AF_INET, ip_.c_str(), &lock.sin_addr);

        char str[32] = {0};
        inet_pton(AF_INET, ip_.c_str(), &lock.sin_addr);

        int n = bind(listenfd_, (const sockaddr *)&lock, len);
        if (n < 0)
        {
            lg(Fatal, "bind Fail,code:%d,str:%s", listenfd_, errno, strerror(errno));
            exit(BINDERR);
        }
        lg(Info, "bind success,code:%d,str:%s", errno, strerror(errno));

        n = listen(listenfd_, 5);
        if (n < 0)
        {
            lg(Fatal, "listen fail,errno:%d,strerror:%s", errno, strerror(errno));
            exit(LISTENERR);
        }
        lg(Info, "listen success,code:%d,str:%s", errno, strerror(errno));
    }

    // 单进程版
    //  void Strat()
    //  {
    //      while (1)
    //      {
    //          // client.sin_family=AF_INET;
    //          // uint16_t port = ntohs(client.sin_port);
    //          // char ip[32];
    //          // //inet_ntop(AF_INET, &(client.sin_addr), ip, sizeof(ip));
    //          // printf("[%s][%d] connect ...\n", port, ip);

    //         struct sockaddr_in client;
    //         socklen_t len = sizeof(client);
    //         memset(&client, 0, len);
    //         int sockfd = accept(listenfd_, (struct sockaddr *)&client, &len);
    //         cout << sockfd << endl;

    //         char buf[1024];
    //         while (1)
    //         {
    //             int n = read(sockfd, buf, sizeof(buf));
    //             if (n < 0)
    //             {
    //                 lg(Warning, "read fail,errno:%d,strerror:%s", errno, strerror(errno));
    //                 continue;
    //             }
    //             buf[n] = 0;
    //             cout << "get a message:" << buf << endl;
    //             string message;
    //             message += "Server#";
    //             message += buf;
    //             write(sockfd, message.c_str(), message.size());
    //         }
    //     }
    // }

    // 多进程版
    // void Strat()
    // {
    //     while (1)
    //     {
    //         // client.sin_family=AF_INET;
    //         // uint16_t port = ntohs(client.sin_port);
    //         // char ip[32];
    //         // //inet_ntop(AF_INET, &(client.sin_addr), ip, sizeof(ip));
    //         // printf("[%s][%d] connect ...\n", port, ip);

    //         struct sockaddr_in client;
    //         socklen_t len = sizeof(client);
    //         memset(&client, 0, len);
    //         int sockfd = accept(listenfd_, (struct sockaddr *)&client, &len);
    //         cout << sockfd << endl;

    //         if (fork() == 0)
    //         {
    //             if (fork() > 0)
    //             {
    //                 return;
    //             }
    //             close(listenfd_);
    //             char buf[1024];
    //             while (1)
    //             {
    //                 int n = read(sockfd, buf, sizeof(buf));
    //                 if (n < 0)
    //                 {
    //                     lg(Warning, "read fail,errno:%d,strerror:%s", errno, strerror(errno));
    //                     continue;
    //                 }
    //                 buf[n] = 0;
    //                 cout << "get a message:" << buf << endl;
    //                 string message;
    //                 message += "Server#";
    //                 message += buf;
    //                 write(sockfd, message.c_str(), message.size());
    //             }
    //         }
    //         waitpid(-1,nullptr,0);//阻塞等待（0）任一进程（-1）
    //         close(sockfd);
    //     }
    // }

    // static void *routine(void *argv)
    // {
    //     pthread_detach(pthread_self());
    //     ThreadData*td=static_cast<ThreadData*>(argv);
    //     char buf[1024];
    //     while (1)
    //     {
    //         int n = read(td->sockfd_, buf, sizeof(buf));
    //         if (n <= 0)
    //         {
    //             // lg(Warning, "read fail,errno:%d,strerror:%s", errno, strerror(errno));
    //             continue;
    //         }
    //         buf[n] = 0;
    //         // cout << "get a message:" << buf << endl;
    //         // string message;
    //         // message += "Server#";
    //         // message += buf;
    //         //write(td->sockfd_, message.c_str(), message.size());
    //     }

    //     delete(td);
    //     return nullptr;
    // }

    // 多线程版
    // void Strat()
    // {
    //     while (1)
    //     {
    //         // client.sin_family=AF_INET;
    //         // uint16_t port = ntohs(client.sin_port);
    //         // char ip[32];
    //         // //inet_ntop(AF_INET, &(client.sin_addr), ip, sizeof(ip));
    //         // printf("[%s][%d] connect ...\n", port, ip);

    //         struct sockaddr_in client;
    //         socklen_t len = sizeof(client);
    //         memset(&client, 0, len);
    //         int sockfd = accept(listenfd_, (struct sockaddr *)&client, &len);
    //         cout << sockfd << endl;

    //         pthread_t tid;
    //         ThreadData *td=new ThreadData(sockfd); 
    //         pthread_create(&tid, nullptr, routine,td);

    //     }
    // }

    //线程池版
    void Strat()
    {
        while (1)
        {
            // client.sin_family=AF_INET;
            // uint16_t port = ntohs(client.sin_port);
            // char ip[32];
            // //inet_ntop(AF_INET, &(client.sin_addr), ip, sizeof(ip));
            // printf("[%s][%d] connect ...\n", port, ip);

            struct sockaddr_in client;
            socklen_t len = sizeof(client);
            memset(&client, 0, len);
            int sockfd = accept(listenfd_, (struct sockaddr *)&client, &len);
            uint16_t port=ntohs(client.sin_port);
            string ip=to_string(ntohl(client.sin_addr.s_addr));
            lg(Info,"get a new connect:%d,ip:%s,sort:%d",sockfd,ip.c_str(),port);
            t.push(sockfd);
        }
    }

    ~TcpServer()
    {}

private:
    int listenfd_;
    uint16_t port_;
    std::string ip_;
    Threadpool<int> t;
};
